home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
367_01
/
futi14as.zoo
/
mv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-22
|
14KB
|
601 lines
/* mv -- move or rename files
Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
This port is also distributed under the terms of the
GNU General Public License as published by the
Free Software Foundation.
Please note that this file is not identical to the
original GNU release, you should have received this
code as patch to the official release. */
#ifdef MSDOS
static char RCS_Id[] =
"$Header: e:/gnu/fileutil/RCS/mv.c 1.4.0.2 90/09/19 12:11:15 tho Exp $";
static char Program_Id[] = "mv";
static char RCS_Revision[] = "$Revision: 1.4.0.2 $";
#define VERSION \
"GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
(sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
#define COPYING \
"This is free software, distributed under the terms of the\n" \
"GNU General Public License. For details, see the file COPYING.\n"
#endif /* MSDOS */
/* Options:
-f, +force Assume a 'y' answer to all questions it would
normally ask, and not ask the questions.
-i, +interactive Require confirmation from the user before
performing any move that would destroy an
existing file.
-u, +update Do not move a nondirectory that has an
existing destination with the same or newer
modification time.
-v, +verbose List the name of each file as it is moved, and
the name it is moved to.
-b, +backup
-S, +suffix
-V, +version-control
Backup file creation. See README.
Written by Mike Parker and David MacKenzie */
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include "system.h"
#include "backupfile.h"
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *getenv ();
extern int errno;
#endif
#ifdef MSDOS
#include <io.h>
#include <gnulib.h>
extern void main (int argc, char **argv);
extern void error (int status, int errnum, char *message, ...);
extern int eaccess_stat (struct stat *statp, int mode);
extern enum backup_type get_version (char *version);
static int isdir (char *fn);
static int movefile (char *from, char *to);
static int do_move (char *from, char *to);
static int copy (char *from, char *to);
static int yesno (void );
static void strip_trailing_slashes (char **path);
static int force_unlink (char *filename);
static void usage (void );
#define unlink(name) force_unlink (name)
#define rename(from, to) (unlink (to) || rename (from, to))
#define strip_trailing_slashes(path) strip_trailing_slashes (&path)
#else /* not MSDOS */
enum backup_type get_version ();
int copy ();
int do_move ();
int isdir ();
int movefile ();
int yesno ();
void error ();
void strip_trailing_slashes ();
void usage ();
#endif /* not MSDOS */
/* The name this program was run with. */
char *program_name;
/* If nonzero, query the user before overwriting files. */
int interactive;
/* If nonzero, do not move a nondirectory that has an existing destination
with the same or newer modification time. */
int update = 0;
/* If nonzero, list each file as it is moved. */
int verbose;
struct option long_options[] =
{
#ifdef MSDOS
{"copying", 0, NULL, 30},
{"version", 0, NULL, 31},
#endif
{"backup", 0, NULL, 'b'},
{"force", 0, NULL, 'f'},
{"interactive", 0, NULL, 'i'},
{"suffix", 1, NULL, 'S'},
{"update", 0, &update, 1},
{"verbose", 0, &verbose, 1},
{"version-control", 1, NULL, 'V'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int c;
int ind;
int errors;
int make_backups = 0;
char *version;
version = getenv ("SIMPLE_BACKUP_SUFFIX");
if (version)
simple_backup_suffix = version;
version = getenv ("VERSION_CONTROL");
program_name = argv[0];
interactive = verbose = update = 0;
errors = 0;
while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, &ind))
!= EOF)
{
switch (c)
{
case 0:
break;
case 'b':
make_backups = 1;
break;
case 'f':
interactive = 0;
break;
case 'i':
interactive = 1;
break;
case 'u':
update = 1;
break;
case 'v':
verbose = 1;
break;
case 'S':
simple_backup_suffix = optarg;
break;
case 'V':
version = optarg;
break;
#ifdef MSDOS
case 30:
fprintf (stderr, COPYING);
exit (0);
break;
case 31:
fprintf (stderr, VERSION);
exit (0);
break;
#endif
default:
usage ();
}
}
if (argc < optind + 2)
usage ();
if (make_backups)
backup_type = get_version (version);
strip_trailing_slashes (argv[argc - 1]);
if (argc > optind + 2 && !isdir (argv[argc - 1]))
error (1, 0, "when moving multiple files, last argument must be a directory");
/* Move each arg but the last onto the last. */
for (; optind < argc - 1; ++optind)
errors |= movefile (argv[optind], argv[argc - 1]);
exit (errors);
}
/* Move file FROM onto TO. Handles the case when TO is a directory.
Return 0 if successful, 1 if an error occurred. */
int
movefile (from, to)
char *from;
char *to;
{
strip_trailing_slashes (from);
if (isdir (to))
{
/* Target is a directory; build full target filename. */
char *cp;
char *newto;
cp = rindex (from, '/');
if (cp)
cp++;
else
cp = from;
newto = (char *) alloca (strlen (to) + 1 + strlen (cp) + 1);
#ifdef MSDOS
/* Here a trailing slash might still be present (needed for
stat()'ing root directories), take care of that. */
if (to[strlen(to) - 1] == '/')
sprintf (newto, "%s%s", to, cp);
else
#endif /* MSDOS */
sprintf (newto, "%s/%s", to, cp);
return do_move (from, newto);
}
else
return do_move (from, to);
}
struct stat to_stats, from_stats;
/* Move FROM onto TO. Handles cross-filesystem moves.
If TO is a directory, FROM must be also.
Return 0 if successful, 1 if an error occurred. */
int
do_move (from, to)
char *from;
char *to;
{
char *to_backup = NULL;
if (lstat (from, &from_stats) != 0)
{
error (0, errno, "%s", from);
return 1;
}
if (lstat (to, &to_stats) == 0)
{
#ifdef MSDOS
if (strcmp (to, from) == 0)
{
error (0, 0, "`%s': can't move file to itself", from);
return 1;
}
#else /* not MSDOS */
if (from_stats.st_dev == to_stats.st_dev
&& from_stats.st_ino == to_stats.st_ino)
{
error (0, 0, "`%s' and `%s' are the same file", from, to);
return 1;
}
#endif /* not MSDOS */
if ((to_stats.st_mode & S_IFMT) == S_IFDIR)
{
error (0, 0, "%s: cannot overwrite directory", to);
return 1;
}
if ((from_stats.st_mode & S_IFMT) != S_IFDIR && update
&& from_stats.st_mtime <= to_stats.st_mtime)
return 0;
if (interactive)
{
fprintf (stderr, "%s: replace `%s'? ", program_name, to);
if (!yesno ())
return 0;
}
if (backup_type != none)
{
to_backup = find_backup_file_name (to);
if (to_backup == NULL)
error (1, 0, "virtual memory exhausted");
if (rename (to, to_backup))
{
if (errno != ENOENT)
{
error (0, errno, "cannot backup `%s'", to);
free (to_backup);
return 1;
}
else
{
free (to_backup);
to_back